package net.xinshi.commons;

import org.apache.http.client.CookieStore;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * @author <a href="mailto:liukuo@xinshi.net">liukuo</a>
 * @version 1.0
 * @description
 * @since 2017/7/19. httpClient 4.5.2版本
 */
public class HttpClientManager452 {
    @Autowired
    long socket_timeout;  //socket timeout
    @Autowired
    long connection_timeout;//连接超时时间
    @Autowired
    boolean staleCheck;
    @Autowired
    int max_total_connections;//总连接数
    @Autowired
    int max_connections_per_route;

    private static PoolingHttpClientConnectionManager clientConnectionManager = null;
    private static CloseableHttpClient httpClient = null;
    private static RequestConfig config = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT).build();
    private final static Object syncLock = new Object();
    private static IdleConnectionMonitorThread scanThread = null;

    /**
     * 创建httpclient连接池并初始化
     */
    @PostConstruct
    private void init() {
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("https", SSLConnectionSocketFactory.getSocketFactory())
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .build();
        clientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        clientConnectionManager.setMaxTotal(max_total_connections);
        clientConnectionManager.setDefaultMaxPerRoute(max_connections_per_route);

        // 扫描无效连接的线程
        scanThread = new IdleConnectionMonitorThread(clientConnectionManager);
        scanThread.start();
    }

    public static CloseableHttpClient getHttpClient() {
        if (httpClient == null) {
            synchronized (syncLock) {
                if (httpClient == null) {
                    CookieStore cookieStore = new BasicCookieStore();
                    httpClient = HttpClients.custom().setConnectionManager(clientConnectionManager).setDefaultCookieStore(cookieStore).setDefaultRequestConfig(config).build();
                }
            }
        }
        return httpClient;
    }
    class IdleConnectionMonitorThread extends Thread {
        private final PoolingHttpClientConnectionManager connMgr;
        private volatile boolean shutdown;

        public IdleConnectionMonitorThread(PoolingHttpClientConnectionManager connMgr) {
            super();
            this.connMgr = connMgr;
        }

        @Override
        public void run() {
            try {
                while (!shutdown) {
                    synchronized (this) {
                        wait(5000);
                        // Close expired connections
                        connMgr.closeExpiredConnections();
                        // Optionally, close connections
                        // that have been idle longer than 30 sec
                        connMgr.closeIdleConnections(30, TimeUnit.SECONDS);
                    }
                }
            } catch (InterruptedException ex) {
                // terminate
            }
        }

        public void shutdown() {
            shutdown = true;
            synchronized (this) {
                notifyAll();
            }
        }

    }

    public long getSocket_timeout() {
        return socket_timeout;
    }

    public void setSocket_timeout(long socket_timeout) {
        this.socket_timeout = socket_timeout;
    }

    public long getConnection_timeout() {
        return connection_timeout;
    }

    public void setConnection_timeout(long connection_timeout) {
        this.connection_timeout = connection_timeout;
    }

    public boolean isStaleCheck() {
        return staleCheck;
    }

    public void setStaleCheck(boolean staleCheck) {
        this.staleCheck = staleCheck;
    }

    public int getMax_total_connections() {
        return max_total_connections;
    }

    public void setMax_total_connections(int max_total_connections) {
        this.max_total_connections = max_total_connections;
    }

    public int getMax_connections_per_route() {
        return max_connections_per_route;
    }

    public void setMax_connections_per_route(int max_connections_per_route) {
        this.max_connections_per_route = max_connections_per_route;
    }
}
